﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Httlgd.DataCenter.Services.Core;
using Httlgd.DataCenter.Services.Core.Common;
using Httlgd.DataCenter.Services.Core.Common.DataTransferObjects;
using System.ServiceModel;
using Httlgd.DataCenter.Services.Core.Messages;
using Httlgd.DataCenter.Services.Core.Logging;

namespace Httlgd.DataCenter.Services.Core.Common.Service
{
    public delegate DataTransferObjectBase BusinessMethodCall<TPayload>(TPayload payload);
    public delegate DataTransferObjectBase BusinessMethodCall();
    public delegate void BusinessVoidMethodCall<TPayload>(TPayload payload);

    public class BusinessService
    {
        public static TResult Execute<TPayload, TResult>(TPayload servicePayload, BusinessMethodCall<TPayload> methodCall)
            where TResult : DataTransferObjectBase
        {
            DataTransferObjectBase result = null;
            ValidationErrorsDTO errors = null;
            //string serviceName = "not set";
            try
            {
                //serviceName = methodCall.Target.ToString() + "." + methodCall.Method.ToString().Substring(methodCall.Method.ToString().IndexOf(" ") + 1, methodCall.Method.ToString().IndexOf("(") - methodCall.Method.ToString().IndexOf(" ") - 1);

                //ContractObjectToXml(metadata, serviceName, "Inbound Metadata");
                //servicePayload = ContractObjectToXml(servicePayload, serviceName, "Inbound Payload ");

                result = methodCall(servicePayload);
            }
            catch (ValidationException validationException)
            {
                errors = validationException.Details;
            }
            //catch (ApplicationException ex)
            //{
            //    ExceptionPolicy.Log(ex);
            //    errors = ex.ToValidationErrors();
            //}
            catch (Exception exception)
            {
                //ExceptionPolicy.Log(exception);
                //LogManager.WriteGeneralLog(exception.Message, "Business execution error.");
                //throw new FaultException(ErrorMessages.BS_GeneralError);
                System.Diagnostics.EventLog.WriteEntry("SMS Service", exception.Message);
            }

            // in case no exception thrown, try to cast the result to ValidationErrorsDTO
            if (errors == null)
            {
                errors = result as ValidationErrorsDTO;
            }

            // if errors found after all, throw them out to client
            if (errors != null && errors.ErrorList.Count > 0)
            {
                //ContractObjectToXml(errors, serviceName, "Outbound Errors  ");

                //TODO: Populate message resource from database using code 
                //errors.PopulateMessages();

                throw new FaultException<ValidationErrorsDTO>(errors, BusinessMessages.BS_001);
            }

            //ContractObjectToXml(result, serviceName, "Outbound Result  ");
            return result as TResult;
        }

        public static TResult Execute<TResult>(BusinessMethodCall methodCall)
            where TResult : DataTransferObjectBase
        {
            DataTransferObjectBase result = null;
            ValidationErrorsDTO errors = null;
            //string serviceName = "not set";
            try
            {
                //serviceName = methodCall.Target.ToString() + "." + methodCall.Method.ToString().Substring(methodCall.Method.ToString().IndexOf(" ") + 1, methodCall.Method.ToString().IndexOf("(") - methodCall.Method.ToString().IndexOf(" ") - 1);

                //ContractObjectToXml(metadata, serviceName, "Inbound Metadata");
                //servicePayload = ContractObjectToXml(servicePayload, serviceName, "Inbound Payload ");

                result = methodCall();
            }
            catch (ValidationException validationException)
            {
                errors = validationException.Details;
            }
            //catch (ApplicationException ex)
            //{
            //    ExceptionPolicy.Log(ex);
            //    errors = ex.ToValidationErrors();
            //}
            catch (Exception exception)
            {
                //ExceptionPolicy.Log(exception);
                LogManager.WriteGeneralLog(exception.Message, "Business execution error.");
                throw new FaultException(ErrorMessages.BS_GeneralError);
            }

            // in case no exception thrown, try to cast the result to ValidationErrorsDTO
            if (errors == null)
            {
                errors = result as ValidationErrorsDTO;
            }

            // if errors found after all, throw them out to client
            if (errors != null && errors.ErrorList.Count > 0)
            {
                //ContractObjectToXml(errors, serviceName, "Outbound Errors  ");

                //TODO: Populate message resource from database using code 
                //errors.PopulateMessages();

                throw new FaultException<ValidationErrorsDTO>(errors, BusinessMessages.BS_001);
            }

            //ContractObjectToXml(result, serviceName, "Outbound Result  ");
            return result as TResult;
        }

        public static void Execute<TPayload>(TPayload servicePayload, BusinessVoidMethodCall<TPayload> methodCall)
        {
            ValidationErrorsDTO errors = null;
            //string serviceName = "not set";
            try
            {
                //serviceName = methodCall.Target.ToString() + "." + methodCall.Method.ToString().Substring(methodCall.Method.ToString().IndexOf(" ") + 1, methodCall.Method.ToString().IndexOf("(") - methodCall.Method.ToString().IndexOf(" ") - 1);

                //ContractObjectToXml(metadata, serviceName, "Inbound Metadata");
                //servicePayload = ContractObjectToXml(servicePayload, serviceName, "Inbound Payload ");

                methodCall(servicePayload);
            }
            catch (Exception exception)
            {
                //ExceptionPolicy.Log(exception);
                LogManager.WriteGeneralLog(exception.Message, "Business execution error.");
                throw new FaultException(ErrorMessages.BS_GeneralError);
            }


            // if errors found after all, throw them out to client
            if (errors != null && errors.ErrorList.Count > 0)
            {
                //ContractObjectToXml(errors, serviceName, "Outbound Errors  ");

                //TODO: Populate message resource from database using code 
                //errors.PopulateMessages();

                throw new FaultException<ValidationErrorsDTO>(errors, BusinessMessages.BS_001);
            }

            //ContractObjectToXml(result, serviceName, "Outbound Result  ");
        }
    }
}
